﻿#pragma once
#include <string>
#include <mutex>
#include <map>
#include <vector>
#include <unordered_map>
#include "thread_lock.h"
#include "base_type.h"

struct DefaultObj
{
	unsigned char v[64];
};

struct DynaObj
{
	DynaObj(char *ptr, size_t len) : ptr_(ptr), len_(len) {}
	char *ptr_;
	size_t len_;
};

template<class Obj, class Mutex = NullMutex>
class ObjectPool
{
public:
	enum E_DEFAULT
	{
		DEFAULT_POOL_OBJ_COUNT = 1024
	};

	struct ObjectPlus
	{
		ObjectPlus() :obj(nullptr), is_use(false) {}
		bool is_use;
		Obj *obj;
	};

	typedef std::unordered_map<uint64, ObjectPlus*> ObjMap;
	typedef std::vector<ObjectPlus*> ObjVec;

	ObjectPool(int count = E_DEFAULT::DEFAULT_POOL_OBJ_COUNT);
	virtual ~ObjectPool();

	ObjectPool& operator=(const ObjectPool &) = delete;
	ObjectPool(const ObjectPool &) = delete;

	void reserve(int count);
	void resize(int initCount);
	void clear();
	
	void push(Obj *obj);
	virtual Obj* pop();
	bool empty()const;

	size_t UseObjCount()const;
	size_t FreeObjCount()const;
	size_t TotalObjCount()const;

	void DebugInfo();

protected:
	ObjectPlus* create(Obj *obj = nullptr)
	{
		ObjectPlus *p = nullptr;
		while ((p = new ObjectPlus()) == nullptr);
		while (obj == nullptr)
			obj = new Obj;
		p->obj = obj;
		return p;
	}
	

private:
	Mutex mutex_;
	ObjVec obj_vec_;
	ObjMap use_obj_map_;

	size_t use_obj_count_;
	size_t free_obj_count_;
	size_t total_obj_count_;
	std::string name_;
};


/// Returns true if the pointer is of the given alignment
inline bool is_aligned_to(const void* ptr, size_t align)
{
	return (reinterpret_cast<uintptr_t>(ptr) & (align - 1)) == 0;
}

template<class T, class Mutex = NullMutex>
class ObjectPoolBlock
{
	ObjectPoolBlock(uint32 entries_per_block);
	~ObjectPoolBlock();

	ObjectPoolBlock(const ObjectPoolBlock&) = delete;
	ObjectPoolBlock& operator=(const ObjectPoolBlock&) = delete;

	uint32* indices_begin() const;
	T* memory_begin() const;
	uint32 free_head_index_;
	const uint32 entries_per_block_;

public:
	static ObjectPoolBlock<T, Mutex>* create(uint32 entries_per_block);
	static void destroy(ObjectPoolBlock<T, Mutex>* ptr);

	template <class... P>
	T* pop(P&&... params);

	void push(const T* ptr);

	void delete_all();

	template <typename F>
	void for_each(const F func) const;

	const T* memory_offset() const;

	uint32 num_allocations() const;
};

// template<class Obj, class Mutex>
// ObjectPool<Obj, Mutex>::ObjectPlus* ObjectPool<Obj, Mutex>::create(Obj *obj){
	
// }
#include "object_pool.inl"
